#include <Precomp.h>
#include <AVUIDispatcher.h>
#include <AVUIContextLayoutManager.h>
#include <AVUITextBlock.h>
#include <AVUIWindow.h>
#include <AVUIGeneralTransform.h>
#include "defs.h"
#include "GameWorld.h"
#include "Player.h"
#include "ClientListener.h"
#include "Application.h"
#include "DetailViewWindow.h"

using namespace AVUI;

REGISTER_ELEMENT_BEGIN(DetailViewWindow)
    REGISTER_DEFAULT_FACTORY()
    REGISTER_ROUTED_EVENT(DetailItemChanged)
REGISTER_ELEMENT_END()


DetailViewWindow::DetailViewWindow() : m_pGameWorld(NULL), m_pCamera(NULL), m_pViewport(NULL), m_pEventSubscription(NULL), 
                                       m_eViewType(eViewType_None), m_isRegisteredForLayoutUpdated(false),
                                       m_pTitle(NULL), m_pResources(NULL)
{
}


DetailViewWindow::~DetailViewWindow() 
{
    if(m_pGameWorld != NULL)
    {
        m_pGameWorld->UnsubscribeEvents(m_pEventSubscription);
    }
}

Size DetailViewWindow::MeasureOverride(const Size& constraintSize)
{   

    if(m_pCamera == NULL)
    {
        m_pCamera = m_pGameWorld->GetListener()->GetSceneManager()->createCamera("DetailViewCamera");
        m_pViewport = m_pGameWorld->GetListener()->GetApp()->GetRenderWindow()->addViewport(m_pCamera, 1, 0.0f, 0.0f, 0.0f, 0.0f);

        m_pViewport->setOverlaysEnabled(false);
        m_pViewport->setBackgroundColour(Ogre::ColourValue(0,0,0));

        m_pEventSubscription = m_pGameWorld->SubscribeEvents(CGameWorld::EventSubscriber(&DetailViewWindow::OnGameWorldEvent, this));

        m_pTitle = (TextBlock*) FindName(object_allocate<String>(L"DetailViewTitle"));
        m_pResources = (TextBlock*) FindName(object_allocate<String>(L"DetailViewResources"));
    }

    if(!m_isRegisteredForLayoutUpdated)
    {
        m_isRegisteredForLayoutUpdated = true;
        add_LayoutUpdated(EventHandler::Create(this, &DetailViewWindow::OnLayoutUpdated));
    }


    return constraintSize;
}



Size DetailViewWindow::ArrangeOverride(const Size& constraintSize)
{
    return constraintSize;
}

void DetailViewWindow::OnRender(AVUI::DrawingContext& drawingContext)
{
}

void DetailViewWindow::OnLayoutUpdated(Object* pSender, EventArgs* pArgs)
{
    remove_LayoutUpdated(EventHandler::Create(this, &DetailViewWindow::OnLayoutUpdated));

    m_isRegisteredForLayoutUpdated = false;

    Rect globalRect = TransformToAncestor(Application::get_Current()->get_MainWindow())->TransformBounds(Rect(get_RenderSize()));
    Rect windowRect(Application::get_Current()->get_PresentationSourceSize());

    float flLeft = globalRect.get_Left() / (1.0f * windowRect.get_Width());
    float flTop = globalRect.get_Top() / (1.0f * windowRect.get_Height());
    float flWidth = (globalRect.get_Width() + 1.0f) / (1.0f * windowRect.get_Width());
    float flHeight = (globalRect.get_Height() + 1.0f) / (1.0f * windowRect.get_Height());

    m_pViewport->setDimensions(flLeft, flTop, flWidth, flHeight);

    m_pCamera->setAspectRatio(
        Ogre::Real(m_pViewport->getActualWidth()) / Ogre::Real(m_pViewport->getActualHeight()));
}


void DetailViewWindow::OnGameWorldEvent(CGameWorldEvent* pGameWorldEvent)
{
    if(pGameWorldEvent->GetEventID() == eGameWorldEventID_ShowPlanetDetail)
    {
        CPlanetEvent* pPlanetEvent = (CPlanetEvent*) pGameWorldEvent;

        ViewPlanet(pPlanetEvent->GetPlanet()->GetPlanetID());
    }
    else if(pGameWorldEvent->GetEventID() == eGameWorldEventID_PlanetResourceUpdated)
    {
        CPlanetEvent* pPlanetEvent = (CPlanetEvent*) pGameWorldEvent;

        if(m_dwIDView == pPlanetEvent->GetPlanet()->GetPlanetID())
        {
            UpdatePlanetText();
        }
    }

}

void DetailViewWindow::ViewPlanet(DWORD dwPlanetID)
{
    m_eViewType = eViewType_Planet;
    m_dwIDView = dwPlanetID;

    CPlanet* pPlanet = m_pGameWorld->GetPlanetByID(m_dwIDView);

    float flBack = 1000.0f;
    m_pCamera->setPosition(Ogre::Vector3(pPlanet->GetXLocation() * 1.0f, pPlanet->GetYLocation() + flBack , -1.73f * flBack));

    // Look back along -Z
    m_pCamera->lookAt(Ogre::Vector3(pPlanet->GetXLocation() * 1.0f, pPlanet->GetYLocation() + flBack / 10.0f, 0.0f));
    m_pCamera->roll(Ogre::Radian(Ogre::Math::PI));

    UpdatePlanetText();

    RoutedEventArgs detailItemChangedEventArgs(get_DetailItemChangedEvent());
    RaiseEvent(&detailItemChangedEventArgs);
}

bool DetailViewWindow::HasPlanetInfo(CPlanet* pPlanet)
{
    CGamePlayer* pPlayer = m_pGameWorld->GetPlayerForLocalPlayer();
    if(pPlayer == NULL)
    {
        return false;
    }

    ETeamFlags eTeamFlag = ETeamIDToETeamFlag(pPlayer->GetTeamID());

    if(pPlanet->GetInfoBitmask() & eTeamFlag)
    {
        return true;
    }

    return false;
}

DWORD DetailViewWindow::GetPlanetColor(CPlanet* pPlanet)
{
    if(!HasPlanetInfo(pPlanet))
    {
        return 0xFF777777;
    }

    return ETeamIDToColor(pPlanet->GetTeamOwner());
}

bool DetailViewWindow::IsPlayerNear(CPlanet* pPlanet, CGamePlayer* pPlayer)
{
    int dx = pPlanet->GetXLocation() - pPlayer->GetXLocation();
    int dy = pPlanet->GetYLocation() - pPlayer->GetYLocation();

    if( (dx * dx + dy * dy) < (c_uiPlanetRadius * c_uiPlanetRadius * 4))
    {
        return true;
    }
    return false;
}

bool DetailViewWindow::IsBombing(CPlanet* pPlanet, CGamePlayer* pPlayer)
{
    if(!(pPlayer->GetFlags() & ePlayerFlag_Bomb))
    {
        return false;
    }

    return IsPlayerNear(pPlanet, pPlayer);
}

bool DetailViewWindow::IsTransporting(CPlanet* pPlanet, CGamePlayer* pPlayer)
{
    if(!(pPlayer->GetFlags() & ePlayerFlag_BeamUp || pPlayer->GetFlags() & ePlayerFlag_BeamDown))
    {
        return false;
    }

    return IsPlayerNear(pPlanet, pPlayer);
}


void DetailViewWindow::UpdatePlanetText()
{
    if(m_eViewType == eViewType_Planet)
    {
        CGamePlayer* pLocalPlayer = m_pGameWorld->GetPlayerForLocalPlayer();
        CPlanet* pPlanet = m_pGameWorld->GetPlanetByID(m_dwIDView);

        if(m_pTitle != NULL)
        {
            m_pTitle->set_Text(object_allocate<String>(pPlanet->GetName()));
        }

        char szResourceText[1024] = { 0 };

        if(pLocalPlayer != NULL && IsBombing(pPlanet, pLocalPlayer))
        {
            strcat_s(szResourceText, sizeof(szResourceText), "Bombardment In Progress\n");
        }

        if(pLocalPlayer != NULL && IsTransporting(pPlanet, pLocalPlayer))
        {
            strcat_s(szResourceText, sizeof(szResourceText), "Transport In Progress\n");
        }

        if(HasPlanetInfo(pPlanet))
        {
            if((pPlanet->GetFlags() & ePlanetFlag_Fuel ||
               pPlanet->GetFlags() & ePlanetFlag_Repair ||
               pPlanet->GetFlags() & ePlanetFlag_Agri))

            {
                bool isAnd = false;

                strcat_s(szResourceText, sizeof(szResourceText), "RESOURCES: ");
                if(pPlanet->GetFlags() & ePlanetFlag_Fuel)
                {
                    if(isAnd)
                    {
                        strcat_s(szResourceText, sizeof(szResourceText), ", ");
                    }
                    strcat_s(szResourceText, sizeof(szResourceText), "FUEL");
                    isAnd = true;
                }

                if(pPlanet->GetFlags() & ePlanetFlag_Repair)
                {
                    if(isAnd)
                    {
                        strcat_s(szResourceText, sizeof(szResourceText), ", ");
                    }
                    strcat_s(szResourceText, sizeof(szResourceText), "REPAIR");
                    isAnd = true;
                }
                if(pPlanet->GetFlags() & ePlanetFlag_Agri)
                {
                    if(isAnd)
                    {
                        strcat_s(szResourceText, sizeof(szResourceText),  ", ");
                    }
                    strcat_s(szResourceText, sizeof(szResourceText), "AGRI");
                    isAnd = true;
                }

                if(isAnd)
                {
                    strcat_s(szResourceText, sizeof(szResourceText), "\n");
                }
            }
            char szArmiesBuf[20] = { 0 };
            sprintf_s(szArmiesBuf, sizeof(szArmiesBuf), "ARMIES: %d", pPlanet->GetArmyCount());

            strcat_s(szResourceText, sizeof(szResourceText), szArmiesBuf);
        }

        if(m_pResources != NULL)
        {  
            m_pResources->set_Text(object_allocate<String>(szResourceText));
        }

    }
}
                                              
